using System;
using System.Collections.Generic;
using System.Collections;
using System.Reflection;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;
using System.Threading;

using Icodeon.Scorm2CC;
using Icodeon.Util;

// Logging
//#if LOG4NET
using log4net;
using log4net.Config;
using log4net.Core;
//#endif

namespace Icodeon.Scorm2CC.GUI
{
    public partial class MainWindow : Form
    {
        private static ILog log;
        private ProgressDialog progressDialog;

        private DirectoryInfo input;
        private FileInfo[] inputFiles;
        private DirectoryInfo output;
        private FileInfo xslFileForScorm1p2;
        private FileInfo xslFileForScorm2004;

        public MainWindow()
        {
            InitializeComponent();

            Scorm2ccDefaults defaults = new Scorm2ccDefaults();
            this.input = defaults.Input;
            this.output = defaults.Output;
            this.xslFileForScorm1p2 = defaults.XslFileForScorm1p2;
            this.xslFileForScorm2004 = defaults.XslFileForScorm2004;
        }

        public MainWindow(
            DirectoryInfo input,
            DirectoryInfo output,
            FileInfo xslFileForScorm1p2,
            FileInfo xslFileForScorm2004)
        {
            InitializeComponent();

            this.input = input;
            this.output = output;
            this.xslFileForScorm1p2 = xslFileForScorm1p2;
            this.xslFileForScorm2004 = xslFileForScorm2004;
        }

        private void MainWindow_Load(object sender, EventArgs e)
        {
            // Logging
            Type type = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType;
            log = LogManager.GetLogger(type);
            DateTime dateTime = DateTime.Now;
            log.Info("SCORM 2 CC launched: "+ dateTime.ToString());


            // Show the welcome dialog
            bool showWelcomeDialogOnStartUp = true;

            try
            {
                // Version
                Assembly assembly = Assembly.GetExecutingAssembly();
                Version vrs = assembly.GetName().Version;
                string longVersionFromVrs = String.Format("{0}.{1}.{2}.{3}", vrs.Major, vrs.Minor, vrs.Build, vrs.MinorRevision);
                this.statusStripVersionLabel.Text = longVersionFromVrs;

                // Input Files
                this.inputFiles = this.input.GetFiles("*.zip");

                // Initial view
                DataTable dataTable = this.CreateDataTable(this.input.GetFiles("*.zip"));
                DataView dataView = new DataView(dataTable);
                this.dataGridView1.DataSource = dataView;
                this.dataGridView1.Refresh();

                string showWelcomeDialogOnStartUpStr = IOUtils.ReadSetting("showWelcomeDialogOnStartUp");
                log.Info(showWelcomeDialogOnStartUpStr);
                showWelcomeDialogOnStartUp = Convert.ToBoolean(showWelcomeDialogOnStartUpStr);
            }
            catch (Exception ex)
            {
                log.Error(ex);
            }

            if (showWelcomeDialogOnStartUp)
            {
                ShowWelcomeDialog();
            }
        }

        private void DoWork(object sender, DoWorkEventArgs e)
        {
            Scorm2ccConverter converter = new Scorm2ccConverter();

            converter.InputFiles = this.inputFiles;
            converter.Output = this.output;
            converter.XslFileForScorm1p2 = this.xslFileForScorm1p2;
            converter.XslFileForScorm2004 = this.xslFileForScorm2004;

            converter.ConversionStart += new ConversionStartEventHandler(Monitor_ConversionStart);
            converter.ConversionComplete += new ConversionCompleteEventHandler(Monitor_ConversionComplete);
            converter.ConversionError += new ConversionErrorEventHandler(Monitor_ConversionError);
            converter.ConversionLog += new ConversionLogEventHandler(Monitor_ConversionLog);
            converter.ConversionProgress += new ConversionProgressEventHandler(Monitor_ConversionProgress);

            converter.StartConversion();
        }

        public void CancelWork()
        {
            this.progressDialog.OverallProgress = 100;
            this.progressDialog.OverallStatus = "All package conversion completed.";
            this.progressDialog.PackageProgress = 100;
            this.progressDialog.PackageStatus = "";

            if (this.progressDialog != null)
            {
                this.progressDialog.Hide();
                this.progressDialog = null;
            }
            this.conversionButton.Enabled = true;
            MessageBox.Show("Conversion cancelled not implemented.");
        }


        private void Monitor_ConversionStart(object sender, ConversionStartEventArgs e)
        {
        }

        private void Monitor_ConversionProgress(object sender, ConversionProgressEventArgs e)
        {
            this.progressDialog.OverallProgress = e.ProgressOverall;
            this.progressDialog.OverallStatus = e.StatusOverall;
            this.progressDialog.PackageProgress = e.ProgressPackage;
            this.progressDialog.PackageStatus = e.StatusPackage;
        }

        private void Monitor_ConversionComplete(object sender, ConversionCompleteEventArgs e)
        {
            if (this.progressDialog != null)
            {
                this.progressDialog.Hide();
                this.progressDialog.Dispose();
                this.progressDialog = null;
            }
            this.conversionButton.Enabled = true;
            this.statusStripStatusLabel.Text = "SCORM 2 CC conversion completed.";
        }

        private void Monitor_ConversionError(object sender, ConversionErrorEventArgs e)
        {
            log.Error(e.Exception.Message, e.Exception);

            MessageBox.Show(String.Format("An error has occured:\n\n{0}", e.Exception.Message),
                "Conversion Error",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error);

            if (this.progressDialog != null)
            {
                this.progressDialog.Hide();
                this.progressDialog.Dispose();
                this.progressDialog = null;
            }
            this.conversionButton.Enabled = true;
            this.statusStripStatusLabel.Text = e.Exception.Message;
        }

        private void Monitor_ConversionLog(object sender, ConversionLogEventArgs e)
        {
            if (e.LogLevel.Equals(Level.Debug) && log.IsDebugEnabled)
            {
                log.Debug(e.Message);
            }
            else if (e.LogLevel.Equals(Level.Info) && log.IsInfoEnabled)
            {
                log.Info(e.Message);
            }
            else if (e.LogLevel.Equals(Level.Warn) && log.IsWarnEnabled)
            {
                log.Warn(e.Message);
            }
            else if (e.LogLevel.Equals(Level.Error) && log.IsErrorEnabled)
            {
                log.Error(e.Message, e.Exception);
            }
            else if (e.LogLevel.Equals(Level.Fatal) && log.IsFatalEnabled)
            {
                log.Fatal(e.Message, e.Exception);
            }
        }

        private void inputButton_Click(object sender, EventArgs e)
        {
            this.SetInputFolder();
        }

        private void outputButton_Click(object sender, EventArgs e)
        {
            this.SetOutputFolder();
        }

        private void importToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.SetInputFolder();
        }

        private void exportToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.SetOutputFolder();
        }

        private void checkForUpdatesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.CheckForUpdates();
        }

        private void checkUpdatesButton_Click(object sender, EventArgs e)
        {
            this.CheckForUpdates();
        }

        private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
        {
            AboutDialog aboutDialog = new AboutDialog();
            aboutDialog.ShowDialog(this);
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void conversionButton_Click(object sender, EventArgs e)
        {
            this.inputFiles = this.GetSelectedFiles();
            if (this.inputFiles.Length == 0)
            {

                MessageBox.Show("No .zip files were selected for conversion to Common Cartridge format.",
                        "No Files Selected Error",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Exclamation);
            }
            else
            {
                this.conversionButton.Enabled = false;
                this.statusStripStatusLabel.Text = "SCORM 2 CC conversion running...";

                // Create a background thread
                BackgroundWorker backgroundWorker = new BackgroundWorker();
                backgroundWorker.DoWork += new DoWorkEventHandler(DoWork);

                // Create a progress form on the UI thread
                this.progressDialog = new ProgressDialog();
                this.progressDialog.Owner = this;

                // Kick off the Async thread
                backgroundWorker.RunWorkerAsync();

                // Lock up the UI with this modal progress form.
                this.progressDialog.ShowDialog(this);
                this.progressDialog = null;
            }
        }

        private FileInfo[] GetSelectedFiles()
        {
            DataView dataView = (DataView)this.dataGridView1.DataSource;
            DataTable dataTable = dataView.Table;
            ArrayList list = new ArrayList();
            foreach (DataRow row in dataTable.Rows)
            {
                if ((Boolean)row["Convert"])
                {
                    string name = (String)row["Name"];
                    IOUtils ioUtils = new IOUtils();
                    FileInfo file = ioUtils.CombineDirectoryNameAndFileName(this.input, name);
                    list.Add(file);
                }
            }

            if (list.Count == 0) { return new FileInfo[0]; }
            return (FileInfo[])list.ToArray(typeof(FileInfo));
        }

        private DataView CreateDataView(DataTable dataTable)
        {
            DataView dataView = new DataView(dataTable);
            dataView.Sort = "Name DESC";
            return dataView;
        }

        private DataTable CreateDataTable(FileInfo[] inputFileList)
        {
            // Instantiate a DataTable object. Set its name property as Packages
            DataTable dataTable = new DataTable("Packages");

            // Get a pair of DataColumn and  DataRow reference
            DataColumn dataColumn;
            DataRow dataRow;

            //  create the first column
            dataColumn = new DataColumn();
            dataColumn.DataType = System.Type.GetType("System.String");
            dataColumn.ColumnName = "Name";
            dataColumn.ReadOnly = true;
            dataColumn.Unique = true;

            //  Now add the column to the column collection
            dataTable.Columns.Add(dataColumn);

            //  Create and add the second column
            dataColumn = new DataColumn();
            dataColumn.DataType = System.Type.GetType("System.Int32");
            dataColumn.ColumnName = "Size";
            dataColumn.ReadOnly = true;
            dataTable.Columns.Add(dataColumn);

            //  Create and add the third column
            dataColumn = new DataColumn();
            dataColumn.DataType = System.Type.GetType("System.Boolean");
            dataColumn.ColumnName = "Convert";
            dataColumn.ReadOnly = false;
            dataTable.Columns.Add(dataColumn);

            // Now instantiate DataRow objects and add them to Rows collection
            foreach (FileInfo file in inputFileList)
            {
                dataRow = dataTable.NewRow();
                dataRow["Name"] = file.Name;
                dataRow["Size"] = file.Length;
                dataRow["Convert"] = true;
                dataTable.Rows.Add(dataRow);
            }

            return dataTable;
        }

        private void SetInputFolder()
        {
            this.inputFolderBrowserDialog.SelectedPath = this.input.FullName;
            this.inputFolderBrowserDialog.Description =
                "Select the folder for importing SCORM .zip files...";
            this.inputFolderBrowserDialog.ShowNewFolderButton = false;

            DialogResult result = this.inputFolderBrowserDialog.ShowDialog(this);
            if (result == DialogResult.OK)
            {
                string selectedPath = this.inputFolderBrowserDialog.SelectedPath;
                this.input = new DirectoryInfo(selectedPath);
                FileInfo[] fileInfos = input.GetFiles("*.zip");
                int count = fileInfos.Length;
                if (count == 0)
                {
                    MessageBox.Show("The selected folder does not contain any .zip files.",
                        "Empty Folder Error",
                        MessageBoxButtons.OK,
                        MessageBoxIcon.Exclamation);
                }
                else
                {
                    DataTable dataTable = this.CreateDataTable(this.input.GetFiles("*.zip"));
                    DataView dataView = new DataView(dataTable);
                    this.dataGridView1.DataSource = dataView;
                    this.dataGridView1.Refresh();
                }
            }
        }

        private void SetOutputFolder()
        {
            this.inputFolderBrowserDialog.SelectedPath = this.output.FullName;
            this.inputFolderBrowserDialog.Description =
                "Select the folder for exporting Common Cartridge .zip files...";
            this.inputFolderBrowserDialog.ShowNewFolderButton = true;

            IOUtils ioUtils = new IOUtils();

            // Create the output directory
            if (!this.output.Exists)
            {
                ioUtils.MakeDirectoriesInPath(this.output);
            }

            DialogResult result = this.inputFolderBrowserDialog.ShowDialog(this);
            if (result == DialogResult.OK)
            {
                string selectedPath = this.inputFolderBrowserDialog.SelectedPath;
                this.output = new DirectoryInfo(selectedPath);
                // Create the output directory
                if (!this.output.Exists)
                {
                    ioUtils.MakeDirectoriesInPath(this.output);
                }
            }
        }


        private void CheckForUpdates()
        {
            Uri urlBase = new Uri("http://www.icodeon.com/scorm2cc");
            string versionInfoFileName = "version.inf";
            string versionFileUrl = urlBase.OriginalString + "/" + versionInfoFileName;
            string versionFileLocal = String.Format("{0}\\{1}", System.Environment.ExpandEnvironmentVariables("%TEMP%"), versionInfoFileName);
            if (File.Exists(versionFileLocal))
            {
                File.Delete(versionFileLocal);
            }
            try
            {
                System.Net.WebClient client = new System.Net.WebClient();
                client.DownloadFile(versionFileUrl, versionFileLocal);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message,
                    "Check Updates Error",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Exclamation);
            }


            if (File.Exists(versionFileLocal))
            {
                TextReader tr = new StreamReader(versionFileLocal);
                string tempStr = tr.ReadLine();
                tr.Close();
                File.Delete(versionFileLocal);

                // The remote version
                string longVersionFromFile = tempStr;
                string shortVersionFromFile = tempStr.Replace(".", String.Empty);

                // The local version
                Version vrs = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
                string longVersionFromVrs = String.Format("{0}.{1}.{2}.{3}", vrs.Major, vrs.Minor, vrs.Build, vrs.MinorRevision);
                string shortVersionFromVrs = String.Format("{0}{1}{2}{3}", vrs.Major, vrs.Minor, vrs.Build, vrs.MinorRevision);

                if (Convert.ToInt32(shortVersionFromVrs) < Convert.ToInt32(shortVersionFromFile))
                {
                    DialogResult result = MessageBox.Show(String.Format("Upgrade from version {0} to {1} is now available. Upgrade now?", longVersionFromVrs, longVersionFromFile), "Upgrade available", MessageBoxButtons.YesNo, MessageBoxIcon.Question);
                    switch (result)
                    {
                        case DialogResult.Yes:
                            {
                                string target = "http://www.codeplex.com/scorm2cc";

                                try
                                {
                                    System.Diagnostics.Process.Start(target);
                                }
                                catch (System.ComponentModel.Win32Exception noBrowser)
                                {
                                    if (noBrowser.ErrorCode == -2147467259)
                                        MessageBox.Show(noBrowser.Message);
                                }
                                catch (System.Exception other)
                                {
                                    MessageBox.Show(other.Message);
                                }
                                break;

                            }
                        default:
                            {
                                break;
                            }
                    }
                }
                else
                {
                    DialogResult result = MessageBox.Show(String.Format("There are no upgrades currently available. You have the latest version of SCORM 2 CC."), "No upgrade available", MessageBoxButtons.OK, MessageBoxIcon.Information);
                }

            }
        }

        private CheckBox ShowWelcomeDialog()
        {
            WelcomeDialog welcomeDialog = new WelcomeDialog();
 
            string showWelcomeDialogOnStartUpStr = IOUtils.ReadSetting("showWelcomeDialogOnStartUp");
            bool showWelcomeDialogOnStartUp = Convert.ToBoolean(showWelcomeDialogOnStartUpStr);
            Control[] controls = welcomeDialog.Controls.Find("showOnStartUpCheckBox", true);
            CheckBox checkBox = (CheckBox)controls[0];
            checkBox.Checked = showWelcomeDialogOnStartUp;
            if (showWelcomeDialogOnStartUp)
            {
                checkBox.CheckState = CheckState.Checked;
            }
            else
            {
                checkBox.CheckState = CheckState.Unchecked;
            }

            // Show the Welcome dialog
            welcomeDialog.ShowDialog(this);
            return checkBox;
        }

        private void showWeclomeDailogMenuItem_Click(object sender, EventArgs e){

            CheckBox checkBox = ShowWelcomeDialog();
            checkBox.Enabled = false;
        }

    }
}